@file:Suppress("unused")

package com.xh.baselibrary.ex

import java.nio.charset.Charset

/**
 * @author sens 2019/3/28
 */

fun ByteArray.startsWith(prefix: String, charset: Charset = Charsets.UTF_8) = this.startsWith(prefix.toByteArray(charset))

fun ByteArray.startsWith(prefix: ByteArray) = this.size >= prefix.size && !prefix.indices.any { this[it] != prefix[it] }


fun ByteArray.endsWith(suffix: String, charset: Charset = Charsets.UTF_8) = this.endsWith(suffix.toByteArray(charset))

fun ByteArray.endsWith(suffix: ByteArray): Boolean {
    val start = this.size - suffix.size
    return start >= 0 && !suffix.indices.any { this[start + it] != suffix[it] }
}


fun ByteArray.contains(content: String, charset: Charset = Charsets.UTF_8) = this.contains(content.toByteArray(charset))

fun ByteArray.contains(content: ByteArray): Boolean {
    val end = this.size - content.size
    return end >= 0 && (0..end).any { i -> !content.indices.any { this[i + it] != content[it] } }
}


fun ByteArray.split(separator: String, limit: Int = 0, charset: Charset = Charsets.UTF_8) = this.split(separator.toByteArray(charset), limit)

fun ByteArray.split(separator: ByteArray, limit: Int = 0): MutableList<ByteArray> {
    if (separator.size == 1) {
        return this.split(separator[0], limit)
    }

    val list = mutableListOf<ByteArray>()
    val one = mutableListOf<Byte>()
    if (limit == 1) {
        one.addAll(this.toTypedArray())
        list.add(one.toByteArray())
        return list
    }

    var index = 0
    while (index < this.size) {
        if (index + separator.size > this.size) {
            one.addAll(this.copyOfRange(index, this.size).toTypedArray())
            break
        }

        if (!separator.indices.any { this[index + it] != separator[it] }) {
            index += separator.size

            if (one.isNotEmpty()) {
                list.add(one.toByteArray())
                one.clear()

                if (limit > 1 && list.size == limit - 1) {
                    one.addAll(this.copyOfRange(index, this.size).toTypedArray())
                    break
                }
            }

            continue
        } else {
            one.add(this[index++])
        }
    }

    if (one.isNotEmpty()) {
        list.add(one.toByteArray())
    }

    return list
}

fun ByteArray.split(separator: Byte, limit: Int = 0): MutableList<ByteArray> {
    val list = mutableListOf<ByteArray>()
    val one = mutableListOf<Byte>()
    if (limit == 1) {
        one.addAll(this.toTypedArray())
        list.add(one.toByteArray())
        return list
    }

    for (i in this.indices) {
        if (this[i] == separator) {
            if (one.isNotEmpty()) {
                list.add(one.toByteArray())
                one.clear()

                if (limit > 1 && list.size == limit - 1) {
                    one.addAll(this.copyOfRange(i + 1, this.size).toTypedArray())
                    break
                }
            }

            continue
        }

        one.add(this[i])
    }

    if (one.isNotEmpty()) {
        list.add(one.toByteArray())
    }

    return list
}


fun ByteArray.replace(oldValue: String, newValue: String, replaceFirst: Boolean = false, charset: Charset = Charsets.UTF_8) =
        this.replace(oldValue.toByteArray(charset), newValue.toByteArray(charset), replaceFirst)

fun ByteArray.replace(oldValue: Byte, newValue: Byte, replaceFirst: Boolean = false) =
        this.replace(byteArrayOf(oldValue), byteArrayOf(newValue), replaceFirst)

fun ByteArray.replace(oldValue: Byte, newValue: ByteArray, replaceFirst: Boolean = false) =
        this.replace(byteArrayOf(oldValue), newValue, replaceFirst)

fun ByteArray.replace(oldValue: ByteArray, newValue: Byte, replaceFirst: Boolean = false) =
        this.replace(oldValue, byteArrayOf(newValue), replaceFirst)

fun ByteArray.replace(oldValue: ByteArray, newValue: ByteArray, replaceFirst: Boolean = false): ByteArray {
    if (oldValue.isEmpty()) {
        return this
    }

    val list = mutableListOf<Byte>()

    var index = 0
    while (index < this.size) {
        if (index + oldValue.size > this.size) {
            list.addAll(this.copyOfRange(index, this.size).toTypedArray())
            break
        }

        if (!oldValue.indices.any { this[index + it] != oldValue[it] }) {
            index += oldValue.size

            if (newValue.isNotEmpty()) {
                list.addAll(newValue.toTypedArray())
                if (replaceFirst) {
                    list.addAll(this.copyOfRange(index, this.size).toTypedArray())
                    break
                }
            }
        } else {
            list.add(this[index++])
        }
    }

    return list.toByteArray()
}